#include "FrameQueue.h"
#include "Log.h"

FrameQueue::FrameQueue(int maxsize, bool keeplast)
{
	m_RIndex = 0;
	m_Windex = 0;
	m_Size = 0;
	m_MaxSize = maxsize;
	m_KeepLast = keeplast;
	m_RIndexShown = 0;
    m_AbortRequest = false;
	for(int i = 0; i < m_MaxSize; i++) {
		if(!(m_Queue[i].frame = av_frame_alloc())){
			LOGD("Frame Queue init error, memory out of range!\n");
		}
	}
}

FrameQueue::~FrameQueue()
{
    for (int i = 0; i < m_MaxSize; i++) {
        Frame *vp = &m_Queue[i];
        av_frame_unref(vp->frame);
        av_frame_free(&vp->frame);
    }
}

void FrameQueue::clear()
{
    m_RIndex = 0;
    m_Windex = 0;
    m_Size = 0;
    m_RIndexShown = 0;
    m_AbortRequest = false;
    for (int i = 0; i < m_MaxSize; i++) {
        Frame *vp = &m_Queue[i];
        av_frame_unref(vp->frame);
    }
}

Frame *FrameQueue::peek()
{
    return &m_Queue[(m_RIndex + m_RIndexShown) % m_MaxSize];
}

Frame *FrameQueue::peekNext()
{
    return &m_Queue[(m_RIndex + m_RIndexShown + 1) % m_MaxSize];
}

Frame *FrameQueue::peekLast()
{
    return &m_Queue[m_RIndex];
}

Frame *FrameQueue::waitForWritable()
{
    /* wait until we have space to put a new frame */
    {
	    AutoLock lock(&m_Cond);
	    while (m_Size >= m_MaxSize &&
	           !m_AbortRequest) {
	        wait();
	    }
	}

    if (m_AbortRequest)
        return NULL;
    return &m_Queue[m_Windex];
}

Frame *FrameQueue::waitForReadable()
{
    /* wait until we have a readable a new frame */
    {
	    AutoLock lock(&m_Cond);
	    while (m_Size - m_RIndexShown <= 0 &&
	           !m_AbortRequest) {
	        wait();
	    }
	}

    if (m_AbortRequest)
        return NULL;
   
    return &m_Queue[(m_RIndex + m_RIndexShown) % m_MaxSize];
}

void FrameQueue::push()
{
    if (++m_Windex == m_MaxSize)
        m_Windex = 0;
    AutoLock lock(&m_Cond);
    m_Size++;
    notify();

}

void FrameQueue::next()
{
    if (m_KeepLast && !m_RIndexShown) {
        m_RIndexShown = 1;
        return;
    }
    Frame *vp = &m_Queue[m_RIndex];
    if(vp->frame->opaque)
        av_freep(&vp->frame->opaque);
    av_frame_unref(vp->frame);
    if (++m_RIndex == m_MaxSize)
        m_RIndex = 0;
    AutoLock lock(&m_Cond);
    m_Size--;
    notify();
}

/* return the number of undisplayed frames in the queue */
int FrameQueue::unDisplayFrame()
{
    return m_Size - m_RIndexShown;
}